/*
REWRITTEN BY XINEF
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "razorfen_downs.h"
#include "Player.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "Cell.h"
#include "CellImpl.h"

/*######
## npc_belnistrasz for Quest 3525 "Extinguishing the Idol"
######*/

Position const PosSummonSpawner[3] =
{
    { 2582.789f, 954.3925f, 52.48214f, 3.787364f  },
    { 2569.42f,  956.3801f, 52.27323f, 5.427974f  },
    { 2570.62f,  942.3934f, 53.7433f,  0.715585f  }
};

enum Belnistrasz
{
    EVENT_CHANNEL                = 1,
    EVENT_IDOL_ROOM_SPAWNER      = 2,
    EVENT_PROGRESS               = 3,
    EVENT_COMPLETE               = 4,
    EVENT_FIREBALL               = 5,
    EVENT_FROST_NOVA             = 6,

    FACTION_ESCORT               = 250,

    PATH_ESCORT                  = 871710,
    POINT_REACH_IDOL             = 17,

    QUEST_EXTINGUISHING_THE_IDOL = 3525,

    SAY_QUEST_ACCEPTED           = 0,
    SAY_EVENT_START              = 1,
    SAY_EVENT_THREE_MIN_LEFT     = 2,
    SAY_EVENT_TWO_MIN_LEFT       = 3,
    SAY_EVENT_ONE_MIN_LEFT       = 4,
    SAY_EVENT_END                = 5,
    SAY_AGGRO                    = 6, // Combat
    SAY_WATCH_OUT                = 7, // 25% chance to target random creature and say on wave spawn

    SPELL_ARCANE_INTELLECT       = 13326,
    SPELL_FIREBALL               = 9053,
    SPELL_FROST_NOVA             = 11831,
    SPELL_IDOL_SHUTDOWN_VISUAL   = 12774, // Hits Unit Entry: 8662
    SPELL_IDOM_ROOM_CAMERA_SHAKE = 12816  // Dummy needs scripting
};

class npc_belnistrasz : public CreatureScript
{
	public:
		npc_belnistrasz() : CreatureScript("npc_belnistrasz") { }

		struct npc_belnistraszAI : public ScriptedAI
		{
			npc_belnistraszAI(Creature* creature) : ScriptedAI(creature)
			{
				instance = creature->GetInstanceScript();
				eventInProgress = false;
				spawnerCount = 0;
			}

			void Reset()
			{
				if (!eventInProgress)
				{
					if (!me->HasAura(SPELL_ARCANE_INTELLECT))
						DoCast(me, SPELL_ARCANE_INTELLECT);

					channeling = false;
					eventProgress = 0;
					spawnerCount  = 0;
					me->SetFlag(UNIT_NPC_FLAGS, GOSSIP_OPTION_QUESTGIVER);
					me->SetReactState(REACT_AGGRESSIVE);
				}
			}

			void EnterCombat(Unit* who)
			{
				if (channeling)
					Talk(SAY_WATCH_OUT, who);
				else
				{
					events.ScheduleEvent(EVENT_FIREBALL, 1000);
					events.ScheduleEvent(EVENT_FROST_NOVA, urand(8000, 12000));
					if (urand(0, 100) > 40)
						Talk(SAY_AGGRO, who);
				}
			}

			void JustDied(Unit* /*killer*/)
			{
				me->DespawnOrUnsummon(5000);
			}

			void sQuestAccept(Player* /*player*/, Quest const* quest)
			{
				if (quest->GetQuestId() == QUEST_EXTINGUISHING_THE_IDOL)
				{
					eventInProgress = true;
					Talk(SAY_QUEST_ACCEPTED);
					me->RemoveFlag(UNIT_NPC_FLAGS, GOSSIP_OPTION_QUESTGIVER);
					me->setFaction(FACTION_ESCORT);
					me->GetMotionMaster()->MovePath(PATH_ESCORT, false);
				}
			}

			void MovementInform(uint32 type, uint32 id)
			{
				if (type == WAYPOINT_MOTION_TYPE && id == POINT_REACH_IDOL)
				{
					channeling = true;
					events.ScheduleEvent(EVENT_CHANNEL, 2000);
				}
			}

			void UpdateAI(uint32 diff)
			{
				if (!eventInProgress)
					return;

				events.Update(diff);

				while (uint32 eventId = events.ExecuteEvent())
				{
					switch (eventId)
					{
						case EVENT_CHANNEL:
							Talk(SAY_EVENT_START);
							DoCast(me, SPELL_IDOL_SHUTDOWN_VISUAL);
							events.ScheduleEvent(EVENT_IDOL_ROOM_SPAWNER, 100);
							events.ScheduleEvent(EVENT_PROGRESS, 120000);
							me->SetReactState(REACT_PASSIVE);
							break;
						case EVENT_IDOL_ROOM_SPAWNER:
							if (Creature* creature = me->SummonCreature(NPC_IDOL_ROOM_SPAWNER, PosSummonSpawner[urand(0,2)], TEMPSUMMON_TIMED_DESPAWN, 4000))
								creature->AI()->SetData(0,spawnerCount);
							if (++spawnerCount < 8)
								events.ScheduleEvent(EVENT_IDOL_ROOM_SPAWNER, 35000);
							break;
						case EVENT_PROGRESS:
						{
							switch (eventProgress)
							{
								case 0:
									Talk(SAY_EVENT_THREE_MIN_LEFT);
									++eventProgress;
									 events.ScheduleEvent(EVENT_PROGRESS, 60000);
									 break;
								case 1:
									Talk(SAY_EVENT_TWO_MIN_LEFT);
									++eventProgress;
									events.ScheduleEvent(EVENT_PROGRESS, 60000);
									break;
								case 2:
									Talk(SAY_EVENT_ONE_MIN_LEFT);
									++eventProgress;
									events.ScheduleEvent(EVENT_PROGRESS, 60000);
									break;
								case 3:
									events.CancelEvent(EVENT_IDOL_ROOM_SPAWNER);
									me->InterruptSpell(CURRENT_CHANNELED_SPELL);
									Talk(SAY_EVENT_END);
									events.ScheduleEvent(EVENT_COMPLETE, 3000);
									break;
							}
							  break;
						}
						case EVENT_COMPLETE:
						{
							DoCast(me, SPELL_IDOM_ROOM_CAMERA_SHAKE);
							me->SummonGameObject(GO_BELNISTRASZS_BRAZIER, 2577.196f, 947.0781f, 53.16757f, 2.356195f, 0, 0, 0.9238796f, 0.3826832f, 3600);
							std::list<WorldObject*> ClusterList;
							Trinity::AllWorldObjectsInRange objects(me, 50.0f);
							Trinity::WorldObjectListSearcher<Trinity::AllWorldObjectsInRange> searcher(me, ClusterList, objects);
							me->VisitNearbyObject(50.0f, searcher);
							for (std::list<WorldObject*>::const_iterator itr = ClusterList.begin(); itr != ClusterList.end(); ++itr)
							{
								if (Player* player = (*itr)->ToPlayer())
								{
									if (player->GetQuestStatus(QUEST_EXTINGUISHING_THE_IDOL) == QUEST_STATUS_INCOMPLETE)
										player->CompleteQuest(QUEST_EXTINGUISHING_THE_IDOL);
								}
								else if (GameObject* go = (*itr)->ToGameObject())
								{
									if (go->GetEntry() == GO_IDOL_OVEN_FIRE || go->GetEntry() == GO_IDOL_CUP_FIRE || go->GetEntry() == GO_IDOL_MOUTH_FIRE)
										go->Delete();
								}
							}
							instance->SetData(GO_BELNISTRASZS_BRAZIER, DONE);
							me->DespawnOrUnsummon();
							break;
						}
						case EVENT_FIREBALL:
							if (me->HasUnitState(UNIT_STATE_CASTING) || !UpdateVictim())
								return;
							DoCastVictim(SPELL_FIREBALL);
							events.ScheduleEvent(EVENT_FIREBALL, 8000);
							break;
						case EVENT_FROST_NOVA:
							if (me->HasUnitState(UNIT_STATE_CASTING) || !UpdateVictim())
								return;
							DoCast(me, SPELL_FROST_NOVA);
							events.ScheduleEvent(EVENT_FROST_NOVA, 15000);
							break;
					}
				}
				if (!channeling)
					DoMeleeAttackIfReady();
			}

		private:
			InstanceScript* instance;
			EventMap events;
			bool eventInProgress;
			bool channeling;
			uint8 eventProgress;
			uint8 spawnerCount;
		};

		CreatureAI* GetAI(Creature* creature) const
		{
			return GetInstanceAI<npc_belnistraszAI>(creature);
		}
};

class npc_idol_room_spawner : public CreatureScript
{
	public:
		npc_idol_room_spawner() : CreatureScript("npc_idol_room_spawner") { }

		struct npc_idol_room_spawnerAI : public NullCreatureAI
		{
			npc_idol_room_spawnerAI(Creature* creature) : NullCreatureAI(creature)
			{
			}

			void SetData(uint32 /*type*/, uint32 data)
			{
				if (data < 7)
				{
					me->SummonCreature(NPC_WITHERED_BATTLE_BOAR, me->GetPositionX(),  me->GetPositionY(),  me->GetPositionZ(),  me->GetOrientation());
					if (data > 0 && me->GetOrientation() < 4.0f)
						me->SummonCreature(NPC_WITHERED_BATTLE_BOAR, me->GetPositionX(),  me->GetPositionY(),  me->GetPositionZ(),  me->GetOrientation());
					me->SummonCreature(NPC_DEATHS_HEAD_GEOMANCER, me->GetPositionX() + (cos(me->GetOrientation() - (M_PI/2)) * 2), me->GetPositionY() + (sin(me->GetOrientation() - (M_PI/2)) * 2), me->GetPositionZ(),  me->GetOrientation());
					me->SummonCreature(NPC_WITHERED_QUILGUARD, me->GetPositionX() + (cos(me->GetOrientation() + (M_PI/2)) * 2), me->GetPositionY() + (sin(me->GetOrientation() + (M_PI/2)) * 2), me->GetPositionZ(),  me->GetOrientation());
				}
				else if (data == 7)
					me->SummonCreature(NPC_PLAGUEMAW_THE_ROTTING, me->GetPositionX(),  me->GetPositionY(),  me->GetPositionZ(),  me->GetOrientation());
			}
		};

		CreatureAI* GetAI(Creature* creature) const
		{
			return GetInstanceAI<npc_idol_room_spawnerAI>(creature);
		}
};

void AddSC_razorfen_downs()
{
    new npc_belnistrasz();
    new npc_idol_room_spawner();
}
